home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 1833 / 1833.xpi / modules / yoonoServerConnection.js < prev    next >
Text File  |  2009-12-16  |  13KB  |  398 lines

  1. var EXPORTED_SYMBOLS = ["YOONO_SERVER"];
  2.  
  3. Components.utils.import("resource://yoono/yoonoPrefs.js");
  4.  
  5. var yoono = {};
  6. var log = {info:function() {},debug:function() {},warn:function(){},error:function (){},fatal:function(){}};
  7.  
  8. // Globals
  9. const CI = Components.interfaces;
  10. const CL = Components.classes;
  11. const XMLHTTPREQUESTCOMPONENT = CL["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance();
  12. const PREFSSERVICE = CL["@mozilla.org/preferences-service;1"].getService(CI.nsIPrefService);
  13. const PREFS = PREFSSERVICE.getBranch("extensions.yoono.");
  14. const OBS = CL['@mozilla.org/observer-service;1'].getService(CI.nsIObserverService);
  15.  
  16.  
  17.  
  18. // -> auto set commandQueueMgr
  19. Components.utils.import("resource://yoono/yoonoCommandQueue.js"); 
  20.  
  21. function Connection() {
  22.     this.wrappedJSObject=this;
  23.     
  24.     this.xmlHttpRequest = XMLHTTPREQUESTCOMPONENT.QueryInterface(CI.nsIXMLHttpRequest);
  25.     this.timer = CL['@mozilla.org/timer;1'].createInstance(CI.nsITimer);
  26.     this.request = null;
  27.     
  28. }
  29.  
  30. Connection.prototype.init = function(y) {
  31.     
  32.     yoono = y;
  33.     log = y.log;
  34.     
  35.     commandQueueMgr.init(y);
  36.     commandQueueMgr.addObserver(this);
  37.     
  38. }
  39.  
  40. Connection.prototype.uninstall = function(y) {
  41.   commandQueueMgr.uninstall();
  42. }
  43.  
  44. Connection.prototype.launch = function (command, arg) {
  45.     if (('connect' != command) && YOONO_PREFS.get('nosynchro')) {
  46.         log.debug("NoSync Pref is true: aborting command");
  47.         return ;
  48.     }
  49.     
  50.     // creer le script et empiler les commandes non transient
  51.     if (command)
  52.         this.addToNextCommandScript(command, arg);
  53.  
  54. }
  55.  
  56.  
  57. Connection.prototype.addToNextCommandScript = function(command, arg) {
  58.     if (('connect' != command) && YOONO_PREFS.get('nosynchro')) {
  59.         //log.debug("NoSync Pref is true: command ignored");
  60.         return ;
  61.     }
  62.     
  63.     var request = this.createRequest(command, arg);
  64.     if (!request.xml)
  65.         return;
  66.     
  67.     if (request.transcient)
  68.         commandQueueMgr.addTranscientRequest(request.xml);
  69.     else
  70.         commandQueueMgr.addTransactionalRequest(request.xml);
  71. }
  72.  
  73.  
  74. Connection.prototype.createRequest = function(command, arg) {
  75.   var userCredential = yoono.main.getUserCredential();
  76.     if (!userCredential) {
  77.         log.debug("Command ignored because no account");
  78.     return({xml:null});
  79.   }
  80.  
  81.   if(userCredential.anonymous && ('connect' != command)) {
  82.         log.debug("Non-connect command ignored because anonymous");
  83.     return({xml:null});
  84.   }
  85.  
  86.     var transientCommand = false;
  87.     var mkcmd = {
  88.         xmlObj : new XML(),
  89.         onNode : function() {}
  90.     };
  91.     
  92.     try {
  93.         switch (command) {
  94.         case 'connect' :
  95.             if(userCredential.anonymous) arg = 'no-sync';
  96.             log.backtrace("connect with arg="+arg);
  97.             switch(arg) {
  98.             case "first-sync" : mkcmd.xmlObj = <connect client-sync-mode="first-sync"/>; break;
  99.             case "manual-sync" : mkcmd.xmlObj = <connect client-sync-mode="manual-sync"/>; break;
  100.             case "auto-sync" : mkcmd.xmlObj = <connect client-sync-mode="auto-sync"/>; break;
  101.             case "no-sync" : mkcmd.xmlObj = <connect client-sync-mode="no-sync"/>; break;
  102.                 default : mkcmd.xmlObj = <connect/>; break;
  103.             }
  104.             transientCommand = true;
  105.             break;
  106.  
  107.         case 'save-all-links' :
  108.             
  109.             log.debug("ADD SAVE ALL");
  110.             
  111.             mkcmd.xmlObj = <save-all-links/>;
  112.             mkcmd.onNode = function(node) {
  113.                 if (node.isFolder())
  114.                     return;
  115.                 
  116.                 this.xmlObj.appendChild(node.setAllAttributes(<link />));
  117.             }
  118.             yoono.bkm.getCurrentTree().traverseNode(mkcmd);
  119.             break;
  120.  
  121.         case 'save-all-links-add' :
  122.             
  123.             log.debug('begin save-all-links-add');
  124.             var notOnServer = arg;
  125.             
  126.             mkcmd.xmlObj = <save-all-links sync-id={YOONO_PREFS.get('syncid')} mode="ADD"/>;
  127.             for each (var nodeList in notOnServer) {
  128.                 for each (var node in nodeList) {
  129.                     mkcmd.xmlObj.appendChild(node.setAllAttributes(<link />));
  130.                 }
  131.             }
  132.  
  133.             log.debug('end save-all-links-add');
  134.             break;
  135.  
  136.         case 'set-sync-id' :
  137.             
  138.             mkcmd.xmlObj = <save-all-links sync-id={YOONO_PREFS.get('syncid')} mode="ADD"/>;
  139.             transientCommand = true;
  140.             break;
  141.  
  142.         case 'add-link':
  143.             
  144.             if (!arg.isFolder())
  145.                 mkcmd.xmlObj = arg.setAllAttributes(<add-link/>);
  146.             
  147.             break;
  148.  
  149.         case 'add-private-folder':
  150.             if (arg.isFolder())
  151.                 mkcmd.xmlObj = arg.setAllAttributes(<add-link private="client"/>);
  152.             break;
  153.  
  154.         case 'remove-private-folder':
  155.             if (arg.isFolder() )
  156.                 mkcmd.xmlObj = arg.setAllAttributes(<remove-link/>);
  157.             break;
  158.  
  159.         case 'publish-folder':
  160.             var node = arg[0];
  161.             var publishedId = arg[1];
  162.             mkcmd.xmlObj = <add-xlink ref={":" + publishedId} path={"/$pub/" +publishedId}/> ;
  163.             var path = node.getPath().toServer;
  164.             var tmp = <update-link/>;
  165.             tmp.appendChild(<old-link path={path}/>);
  166.             tmp.appendChild(<new-link path={path} id={publishedId}/>);
  167.             mkcmd.xmlObj += tmp;
  168.             break;
  169.  
  170.         case 'unpublish-folder':
  171.             var node = arg[0];
  172.             var publishedId = arg[1];
  173.             mkcmd.xmlObj = <remove-xlink ref={":" + publishedId} path={"/$pub/" +publishedId}/> ;
  174.             var tmp = <update-link/>;
  175.             var path = node.getPath().toServer;
  176.             tmp.appendChild(<old-link path={path} id={publishedId}/>);
  177.             tmp.appendChild(<new-link path={path}/>);
  178.             mkcmd.xmlObj += tmp;
  179.             break;
  180.  
  181.         case 'remove-link':
  182.             
  183.             mkcmd.xmlObj = arg.setAllAttributes(<remove-link/>);
  184.             
  185.             break;
  186.  
  187.         case 'update-link':
  188.             var oldNode = arg[0];
  189.             var newNode = arg[1];
  190.             if (oldNode.isAcceptable() && !newNode.isAcceptable()) {
  191.                 this.addToNextCommandScript('remove-link', oldNode);
  192.                 return;
  193.             }
  194.             if (!oldNode.isAcceptable() && newNode.isAcceptable()) {
  195.                 this.addToNextCommandScript('add-link', newNode);
  196.                 return;
  197.             }
  198.             if (!oldNode.isAcceptable() && !newNode.isAcceptable()) {
  199.                 return;
  200.             }
  201.             
  202.             if (!oldNode.isFolder()) {
  203.                 mkcmd.xmlObj = <update-link/>;
  204.                 mkcmd.xmlObj.appendChild(oldNode.setAllAttributes(<old-link/>));
  205.                 mkcmd.xmlObj.appendChild(newNode.setAllAttributes(<new-link/>));
  206.             }
  207.             
  208.             break;
  209.  
  210.         case 'load-all-links' :
  211.             // The load-all-links command is always processed last, whatever its position in the request
  212.             mkcmd.xmlObj = <load-all-links/>;
  213.             break;
  214.  
  215.         case 'compute-recommended-links':
  216.             var newbkmarg = 'url:' + arg.url + ',title:' + arg.title;
  217.             mkcmd.xmlObj = <compute-recommended-links
  218.                 url={arg.url}
  219.                 client-newbkm={newbkmarg}
  220.                 size={1}
  221.                 />;
  222.             transientCommand = true;
  223.             break;
  224.  
  225.         default:
  226.             log.error ('no such command in yoonoService.createRequest : ' + command);
  227.             break;
  228.         }
  229.         
  230.     } catch(e) {
  231.         log.exception(e);
  232.     }
  233.     
  234.     return {
  235.         xml : mkcmd.xmlObj,
  236.         transcient : transientCommand,
  237.         overrideSyncId : false
  238.     };
  239. }
  240.  
  241. // handle the response to the request containing the commands stored in runningScript and runningFile
  242. // according to response, it might be necessary to run again the commands after they were updated
  243. //
  244. // (be warn, $this isn't $this! because this function is called witout his environnement)
  245. Connection.prototype.onSendingRequest = function(req) {
  246.     
  247.     yoono.dialogs.setThrobberBusy(true);
  248.     
  249. }
  250.  
  251. Connection.prototype.onRequestError = function(req) {
  252.     OBS.notifyObservers (this, "yoono-get-response", "error");
  253.     
  254.     yoono.dialogs.setThrobberFailed();
  255. }
  256.  
  257. var safePreferences = {
  258.   bookmarksLastModified: true,
  259.   synchroaction: true,
  260.   synchroask : true,
  261.   syncid : true,
  262.   userid : true
  263. }
  264. Connection.prototype.onRequestSuccess = function(req, result) {
  265.     
  266.     // Notify each request (primary for unit testing)
  267.   try {
  268.     OBS.notifyObservers (this, "yoono-get-response", result);
  269.   } catch(e) {log.exception(e)}
  270.   
  271.   // Handle commands to update preferences
  272.   yoono.main.getServerContextData(result);
  273.     
  274.     var newCommand = false;
  275.     var replace = false;
  276.     yoono.dialogs.setThrobberBusy(false);
  277.     
  278.     // creation d'un nouvel utilisateur
  279.     if (!YOONO_PREFS.get('userid'))
  280.         YOONO_PREFS.set('userid', result.context['user-id'].toString(), PREFS.PREF_STRING);
  281.     
  282.     // If invalid Id, do nothing (handled by sidebar that)
  283.     if (result['display-error'].@code == 'ERROR_INVALID_USER_ID') {
  284.         return;
  285.     }
  286.     
  287.     var requestSync = result['request-sync'].@code;
  288.     
  289.     if (result['display-error'].@code == 'ERROR_INTERNAL_ERROR')
  290.         return log.error("Internal error");
  291.     
  292.     // Sync id was different on server
  293.     if (requestSync == 'REQUEST_SYNC_INVALID_SYNC_ID') {
  294.         yoono.main.addStat(['invalid_sync_id']);
  295.         log.debug("request-sync sync-mode="+result['request-sync'].@['client-sync-mode']);
  296.     var serverLinks = result['request-sync'].@['link-count'];
  297.     var clientLinks = yoono.bkm.getNbBkms();
  298.         log.debug("Nb of bkms on server : " + serverLinks);
  299.         log.debug("Nb of bkms on client : " + clientLinks);
  300.         // ask user
  301.         if( result['request-sync'].@['client-sync-mode'] == "manual-sync" ) {
  302.       // When user enables sync and no link on server, export !
  303.             YOONO_PREFS.set('synchroaction', 'merge', PREFS.PREF_STRING);
  304.       if(0 == serverLinks) {
  305.         YOONO_PREFS.set('synchroaction', 'export', PREFS.PREF_STRING);
  306.       } else {
  307.         if (YOONO_PREFS.get('synchroask')) // don't ask for unittest (there is no way to set this pref to false, except manually!)
  308.           yoono.dialogs.setDialog('synchroask');
  309.       }
  310.         } else if( result['request-sync'].@['client-sync-mode'] == "first-sync" ) {
  311.             YOONO_PREFS.set('synchroaction', 'export', PREFS.PREF_STRING);
  312.         } else if( result['request-sync'].@['client-sync-mode'] == "no-sync" ) {
  313.             return;
  314.         } else {
  315.             YOONO_PREFS.set('synchroaction', 'import', PREFS.PREF_STRING);
  316.       // If no link on server, sync has been disabled on another client : disable this client sync
  317.       if(0 == serverLinks) {
  318.               YOONO_PREFS.set('nosynchro', true, PREFS.PREF_BOOL);
  319.       } else {
  320.         // Test difference between number of bkms on server and on client.
  321.         // if difference > some threshold, ask user.
  322.         var threshold = YOONO_PREFS.get('bkm.ask.threshold') || 10;
  323.         if(Math.abs(serverLinks - clientLinks) > threshold && YOONO_PREFS.get('synchroask')) { // don't ask for unittest (there is no way to set this pref to false, except manually!)
  324.           YOONO_PREFS.set('synchroaction', 'merge', PREFS.PREF_STRING);
  325.           log.debug("Difference > threshold, asking what to do");
  326.           yoono.dialogs.setDialog('synchroask');
  327.         }
  328.       }
  329.         }
  330.  
  331.         log.debug("REQUEST_SYNC_INVALID_SYNC_ID: must perform '" + YOONO_PREFS.get('synchroaction') + "'");
  332.         if (YOONO_PREFS.get('synchroaction') == 'merge' || YOONO_PREFS.get('synchroaction') == 'import') {
  333.             // Re run the same commands, with the server syncid
  334.             newCommand = yoono.server.createRequest('load-all-links');
  335.             newCommand.overrideSyncId = result['request-sync'].@['server-sync-id'];
  336.         }
  337.         else if (YOONO_PREFS.get('synchroaction') == 'export') {
  338.             // Overwrite running command with an save-all-links command
  339.             
  340.             newCommand = yoono.server.createRequest('save-all-links');
  341.             
  342.             yoono.dialogs.synchroinfos('export', yoono.bkm.bookmarksNumber() );
  343.         }
  344.         else if (YOONO_PREFS.get('nosynchro')) {
  345.       // In case of user registration, wizard might be waiting for the end of the sync :
  346.           OBS.notifyObservers (this,"yoono-synchro-end",YOONO_PREFS.get('synchroaction'));
  347.             YOONO_PREFS.resetSynchro();
  348.             return;
  349.         } else { // rajoute une securite au cas ou la valeur a ete modifiee
  350.             YOONO_PREFS.resetSynchro();
  351.             
  352.             newCommand = yoono.server.createRequest('load-all-links');
  353.         }
  354.     } else if (requestSync == 'REQUEST_SYNC_NEW_USER') {
  355.         // Overwrite running command with an save-all-links command
  356.         newCommand = yoono.server.createRequest('save-all-links');
  357.     } else {
  358.     log.debug('Nothing to do : notify so that sidebar wizard knows it can proceed, but knows sync was not necessary');
  359.         OBS.notifyObservers (this,"yoono-synchro-useless",YOONO_PREFS.get('synchroaction'));
  360.   }
  361.  
  362.     // The load-all-links command is always processed last, whatever its position in the request
  363.     var importlinks = result['import-links'];
  364.     if (importlinks.@code == 'MSG_LINKS_LOADED') {
  365.         
  366.         // If some persistent commands are in the 'next' commands buffers, it means new modifications have been made by the user
  367.         // The imported links must not be used then, in order not to undo these new modifications.
  368.         // The load-all-links command is added to the 'next' commands buffers to be performed at the end of the request
  369.         // that sends the new modifications
  370.         if(commandQueueMgr.nextPersistentCommandIsEmpty()) {
  371.             log.debug('Next command is empty, processing loadAllLinks');
  372.             
  373.             var resp = yoono.bkm.loadAllLinks(importlinks.elements('link'));
  374.             
  375.             if (resp.action == 'import') {
  376.                 yoono.dialogs.synchroinfos("import", resp.imported);
  377.             } else if (resp.action == 'merge') {
  378.                 yoono.dialogs.synchroinfos("merge", resp.added);
  379.             }
  380.             // was loadAllLinks successful ?
  381.             if( resp.clearCommands == true ) {
  382.                 // perform a set-sync-id
  383.                 newCommand = yoono.server.createRequest('set-sync-id');
  384.             }
  385.         } else {
  386.             log.debug('Next command not empty, discarding loaded links and queueing load-all-links again');
  387.             yoono.server.addToNextCommandScript('load-all-links');
  388.         }
  389.     }
  390.     //log.debug(" new Command : "+(newCommand?newCommand.xml.toXMLString():"no")+" from "+req.map(function (r){return r.toXMLString();}).join(' \n')+" => "+result.toXMLString());
  391.     return newCommand;
  392.     
  393. }
  394.  
  395.  
  396.  
  397.  
  398. var YOONO_SERVER = new Connection();